<?php

namespace Modules\Inventory\Repository;

use App\Services\InventoryService;
use App\Services\KingDeeService;
use App\Services\UnitService;
use Illuminate\Support\Facades\DB;
use Modules\Inventory\Models\TransferOrder;
use Modules\Inventory\Models\TransferOrderDetail;
use App\Enums\InvTransDocType;
use App\Enums\OrderNoPrefix;
use Modules\Production\Service\TaskScanService;

/**
 * 调拨单相关
 * Class TransferOrderRepository
 * @package Modules\Inventory\Repository
 */
class TransferOrderRepository
{

    /**
     * 调拨单提交处理
     * @param $postData
     * @return bool
     * @throws \Throwable
     */
    static public function storeBy($postData){

        try{
            DB::beginTransaction();
            //保存调拨单据
            $transferOrder = self::saveTransferOrder($postData);

            foreach ($transferOrder['detail'] as $orderItem){
                //原始库存扣减
                self::deductInv($transferOrder,$orderItem);
                //目标库存增加
                self::increaseInv($transferOrder,$orderItem);
            }

            //推送金蝶
            self::pushKingDee($transferOrder['id']);

            DB::commit();

            return true;

        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * 扣减原始库存
     * @param $postData
     * @param $transferOrder
     * @return bool
     */
    static public function deductInv($transferOrder,$transferOrderItem){
        return InventoryService::decInventory(
            $transferOrderItem['cargo_code'],
            $transferOrder['docno'],
            $transferOrder['id'],
            InvTransDocType::TRANSFER_ORDER->value,
            $transferOrderItem['material_no'],
            $transferOrderItem['from_location'],
            $transferOrderItem['from_lotnum'],
            $transferOrderItem['qty'],
            $transferOrderItem['org_code']
        );
    }

    /**
     * 增加目标库位库存
     * @param $invInfo
     * @param $transferOrder
     * @param $transferOrderItem
     */
    static public function increaseInv($transferOrder,$transferOrderItem){

        $invSave = [
            'org_code'      => $transferOrderItem['org_code'],
            'cargo_code'    => $transferOrderItem['cargo_code'],
            'supplier_code' => $transferOrderItem['supplier_code'],
            'doc_id'        => $transferOrder['id'],
            'docno'         => $transferOrder['docno'],
            'doc_type'      => InvTransDocType::TRANSFER_ORDER->value,
            'material_no'   => $transferOrderItem['material_no'],
            'location'      => $transferOrderItem['to_location'],
            'qty'           => $transferOrderItem['qty'],
            'unit'          => $transferOrderItem['unit'],
            'lotnum'        => $transferOrderItem['to_lotnum'],
        ];
        return InventoryService::addInv($invSave);
    }

    /**
     * 调拨单据保存
     * @param $postData
     * @return array
     */
    static public function saveTransferOrder($postData){

        $fristInv = InventoryRepository::getById($postData[0]['inv_id']);

        $transferOrder = [
            'docno'     => UnitService::createDocno('DB'),
            'org_code'  => $fristInv->org_code,
            'status'    => 1
        ];
        $transferOrderId = (new TransferOrder())->storeBy($transferOrder);

        $details = [];
        foreach ($postData as $val){
            $invInfo = InventoryRepository::getById($val['inv_id']);
            if($invInfo->org_code != $fristInv->org_code){
                throw new \Exception('不支持跨组织调拨');
            }
            $details[] = [
                'org_code'      => $invInfo->org_code,
                'cargo_code'    => $invInfo->cargo_code,
                'order_id'      => $transferOrderId,
                'material_no'   => $invInfo->material_no,
                'from_location' => $invInfo->location,
                'from_lotnum'   => $invInfo->lot_num,
                'from_wms'      => TaskScanService::getWmsCodeByLocation($invInfo->location),
                'to_location'   => $val['to_location'],
                'to_lotnum'     => empty($val['to_lotnum']) ? $invInfo->lot_num : $val['to_lotnum'],
                'to_wms'        => TaskScanService::getWmsCodeByLocation($val['to_location']),
                'qty'           => $val['qty'],
                'unit'          => $invInfo->unit,
                'supplier_code' => $invInfo->supplier_code,
                'creator_id'    => UnitService::getUserId(),
                'created_at'    => time(),
                'updated_at'    => time(),
            ];

        }

        $transferOrder['id']        = $transferOrderId;
        $transferOrder['detail']    = $details;

        TransferOrderDetail::insert($details);

        return $transferOrder;

    }

    /**
     * 调拨单据推送金蝶
     * @param $transferOrder
     */
    static public function pushKingDee($transferOrderId){

        $transferOrder = self::getTransferOrderById($transferOrderId);

        $details = self::getTransferOrderGroupById($transferOrderId);

        $order = [
            'FBILLTYPEID'   => 'STK_TransferDirect',
            'FBILLNO'       => $transferOrder->docno,
            'FORGID'        => $transferOrder->org_code,
            'FDATE'         => date('Y-m-d H:i:s'),
        ];

        foreach ($details->toArray() as $value){

            //跳过库内调拨
            if($value['from_wms'] == $value['to_wms']){
                continue;
            }
            $order['FEntity'][] = [
                'FOwnerTypeId'  => 'BD_OwnerOrg',
                'FOwnerId'      => $transferOrder->org_code,
                'FMATERIALID'   => $value['material_no'],
                'FUNITID'       => $value['unit'],
                'FQTY'          => $value['qty'],
                'FSTOCKID'      => $value['from_wms'],//调出仓
                'FDESTSTOCKID'  => $value['to_wms'],//调入仓
                'FNOTE'         => ''
            ];
        }

        if(empty($order['FEntity'])){
            $transferOrder->save(['status' => 3]);//无需推送金蝶
            return true;
        }else{
            $transferOrder->save(['status' => 1]);//推送金蝶成功
            return (new KingDeeService())->form('TVJB_DJWMSDJ')->invokeSave($order);
        }

    }

    /**
     * 分步式调出提交
     * @param $postData
     */
    static public function setByOut($postData){
        try {
            DB::beginTransaction();
            self::saveSetByOutOrder($postData);
            DB::commit();
            return true;
        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * 分步式调出单据保存
     * @param $postData
     * @return array
     * @throws \Exception
     */
    static public function saveSetByOutOrder($postData){
        $fristInv = InventoryRepository::getById($postData[0]['inv_id']);

        $transferOrder = [
            'docno'         => UnitService::createDocno(OrderNoPrefix::NO_FBSDB->value),
            'org_code'      => $fristInv->org_code,
            'status'        => 0,
            'order_type'    => 2,
            'trans_status'  => 0
        ];
        $transferOrderId = (new TransferOrder())->storeBy($transferOrder);

        $details = [];
        foreach ($postData as $val){
            $invInfo = InventoryRepository::getById($val['inv_id']);
            if($invInfo->org_code != $fristInv->org_code){
                throw new \Exception('不支持跨组织调拨');
            }

            //分配库存
            InventoryService::assignInvById(
                $transferOrderId,
                $transferOrder['docno'],
                InvTransDocType::TRANSFER_ORDER->value,
                $val['inv_id'],
                $val['qty']
            );

            $details[] = [
                'org_code'      => $invInfo->org_code,
                'cargo_code'    => $invInfo->cargo_code,
                'order_id'      => $transferOrderId,
                'material_no'   => $invInfo->material_no,
                'from_location' => $invInfo->location,
                'from_lotnum'   => $invInfo->lot_num,
                'from_inv_id'   => $val['inv_id'],
                'from_wms'      => TaskScanService::getWmsCodeByLocation($invInfo->location),
                'to_location'   => '',
                'to_lotnum'     => '',
                'to_wms'        => '',
                'qty'           => $val['qty'],
                'unit'          => $invInfo->unit,
                'supplier_code' => $invInfo->supplier_code,
                'creator_id'    => UnitService::getUserId(),
                'created_at'    => time(),
                'updated_at'    => time(),
            ];

        }

        $transferOrder['id']        = $transferOrderId;
        $transferOrder['detail']    = $details;

        TransferOrderDetail::insert($details);

        return $transferOrder;
    }

    /**
     * 根据箱号查询未调入的调出单
     * @param $lotnum
     * @return mixed
     */
    static public function getOutByLotnum($lotnum,$params){

        $transOrderDetailModel = new TransferOrderDetail();

        if(isset($params['order_id']) && $params['order_id'] != ''){
            $transOrderDetailModel = $transOrderDetailModel->where('order_id',$params['order_id']);
        }

        $lotnumList = $transOrderDetailModel->where('from_lotnum',$lotnum)->with('order','material')->whereHas('order',function($query) use($lotnum){
            $query->where('order_type',2)->where('trans_status',0);
        })->get()->toArray();

        if(empty($lotnumList)){
            throw new \Exception(isset($params['order_id']) && $params['order_id'] != '' ? '当前调出单不存在扫描的箱号' : '该箱号不存在未调入的单据');
        }

        foreach ($lotnumList as &$item){
            $item['order']['detail'] = TransferOrderDetail::where('order_id',$item['order']['id'])->with('material')->get()->toArray();
        }

        return $lotnumList;

    }

    /**
     * 分步式调入提交
     * @param $postData
     * @return mixed
     */
    static public function setByInbound($postData){

        $transferOrder = self::getTransferOrderById($postData['order_id']);

        if(!$transferOrder){
            throw new \Exception('order_id不存在');
        }

        $transferOrder = $transferOrder->toArray();

        $detailList = $transferOrder['detail'];
        if(count($detailList) != count($postData['detail'])){
            throw new \Exception('调入数量必须与调出数一致');
        }

        $detailList = array_column($detailList,null,'id');

        try{

            DB::beginTransaction();

            foreach ($postData['detail'] as $item){

                if(!array_key_exists($item['detail_id'],$detailList)){
                    throw new \Exception("子项id[{$item['detail_id']}]不存在");
                }

                $outItem = $detailList[$item['detail_id']];
                if($item['qty'] != $outItem['qty']){
                    throw new \Exception("箱号[{$outItem['from_lotnum']}]品号[{$outItem['material_no']}]调入数量必须和调出数量一致");
                }

                $toWms = TaskScanService::getWmsCodeByLocation($item['to_location']);

                if($outItem['from_wms'] != $toWms){
                    //throw new \Exception("箱号[{$outItem['from_lotnum']}]品号[{$outItem['material_no']}]不能跨组织调拨");
                }

                TransferOrderDetail::where('id',$outItem['id'])->update([
                    'to_wms'        => $toWms,
                    'to_location'   => $item['to_location'],
                    'to_lotnum'     => $item['to_lotnum'],
                ]);

                //按分配扣减调拨出库库存
                InventoryService::decInventoryByAssign(
                    $transferOrder['docno'],
                    $transferOrder['id'],
                    InvTransDocType::TRANSFER_ORDER->value,
                    $outItem['from_inv_id'],
                    $outItem['qty']
                );

                //增加调拨入库库存
                InventoryService::addInv([
                    'org_code' => $outItem['org_code'],
                    'cargo_code' => $outItem['cargo_code'],
                    'supplier_code' => $outItem['supplier_code'],
                    'doc_id' => $transferOrder['id'],
                    'docno' => $transferOrder['docno'],
                    'doc_type' => InvTransDocType::TRANSFER_ORDER->value,
                    'material_no' => $outItem['material_no'],
                    'location' => $item['to_location'],
                    'qty' => $outItem['qty'],
                    'unit' => $outItem['unit'],
                    'lotnum' => $item['to_lotnum']
                ]);

            }

            //更新调拨单状态
            TransferOrder::where('id',$transferOrder['id'])->update([
                'trans_status' => 1
            ]);

            self::pushKingDee($transferOrder['id']);

            DB::commit();

            return true;//$postData;

        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }

    }

    /**
     * 根据调拨单id查询一条单据信息
     * @param $id
     * @return mixed
     */
    static public function getTransferOrderById($id){
        return TransferOrder::with('detail')->find($id);
    }

    static public function getTransferOrderGroupById($id){
        return TransferOrderDetail::select('material_no','from_wms','unit','to_wms',DB::raw('sum(qty) as qty'))
        ->where('order_id',$id)
        ->groupBy('material_no','unit','from_wms','to_wms')
        ->get();
    }

    /**
     * 调拨单据头列表
     * @param $params
     * @return mixed
     */
    static public function getList($params){

        $builder = self::getWhere($params);

        $limit = isset($params['limit']) ? $params['limit'] : 100;

        return $builder->orderBy('id','desc')->with(['user'=>function ($query) {
            $query->select("username");
        }])->paginate($limit);

    }

    /**
     * 调拨单据头列表筛选
     * @param $params
     * @return TransferOrder
     */
    static public function getWhere($params){

        $builder = new TransferOrder();

        $canQueryField = $builder->getFields();
        foreach($params as $key => $val){
            if(!in_array($key,$canQueryField) || $val == ''){
                continue;
            }

            $builder = $builder->where($key,$val);

        }

        return $builder;

    }

}
